// *** LICENSE HEADER ***
// Filename: ./gui.cpp
// This file is part of Nodewarz 0.1
// Nodewarz is a 3d OpenGL strategy game
// Copyright (C) 2007 CZestmyr
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License along
// with this program; if not, write to the Free Software Foundation, Inc.,
// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
// *** END LICENSE HEADER ***
#include "gui.h"

gui::gui(engine* newParent){
    parent = newParent;
    first = NULL;
    last = NULL;
    lastActivated = NULL;
    guielement::SetColors(0, 0, 128, 255, 255, 255);
}

gui::~gui(){
    guielement* it = first;
    guielement* toDel;
    while (it != NULL){
        toDel = it;
        it = it->GetNext();
        delete toDel;
    }
}

void gui::Click(int x, int y){
    guielement* it = first;
    int result;

    //First, deactivate the previously activated gui element
    if (lastActivated != NULL){
        lastActivated->Deactivate();
        lastActivated = NULL;
    }

    //Then, click all the elements, until one of them returns its ID (which means, it was
    //clicked) and then set it as the last activated.
    while (it != NULL){
        result = it->Click(x, y);
        if (result != 0){
            lastActivated = it;
            it->Activate();
            return;
        }
        it = it->GetNext();
    }
}

void gui::Release(int x, int y){
    guielement* it = first;
    bool released = false;
    int result, firstReleased;

    //Release click on all the gui elements and set firstReleased to the first one of them
    while (it != NULL){
        result = it->Release(x, y);
        it = it->GetNext();
        if (!released && result != 0){
            firstReleased = result;
            released = true;
        }
    }

    //Call the callback function for gui events with the first released element's ID
    if (released)
        guiHandlerCallback(parent, firstReleased);
}

void gui::Activate(int id){
    guielement* it = first;

    while (it != NULL){
        if (it->GetId() == id){
            it->Activate();
            lastActivated = it;
        }
        it = it->GetNext();
    }
}

void gui::KeyPress(SDLKey key, char c){
    if (!lastActivated) return;

    lastActivated->KeyPress(key, c);

    if (key == SDLK_RETURN)
        guiHandlerCallback(parent, lastActivated->GetId());
}

void gui::SetCallback(void (&newCallback)(engine*, int)){
    guiHandlerCallback = newCallback;
}

void gui::CreateButton(int x, int y, int w, int h, const char* text, int id){
    guielement* newButton = (guielement*) new button(id, x, y, w, h, text);
    push_backElement(newButton);
}

void gui::CreateLabel(int x, int y, int fontSize, const char* text, int id){
    guielement* newLabel = (guielement*) new label(id, x, y, fontSize, text);
    push_backElement(newLabel);
}

void gui::CreateNumberField(int x, int y, int w, int h, const char* text, int fontHeight, int maxval, int maxlen, int id){
    guielement* newNumberfield = (guielement*) new numberfield(id, x, y, w, h, fontHeight, maxval, text, maxlen);
    push_backElement(newNumberfield);
}

void gui::CreateTextField(int x, int y, int w, int h, const char* text, int fontHeight, int maxlen, int id){
    guielement* newTextfield = (guielement*) new textfield(id, x, y, w, h, fontHeight, text, maxlen);
    push_backElement(newTextfield);
}

void gui::CreateColorSelector(int x, int y, int selection, int id){
    guielement* newColorselector = (guielement*) new colorselect(x, y, selection, id);
    push_backElement(newColorselector);
}

void gui::CreateColorViewer(int x, int y, int w, int h, int id){
    guielement* newColorviewer = (guielement*) new colorviewer(x, y, w, h, id);
    push_backElement(newColorviewer);
}

void gui::CreateCanvas(int x, int y, int w, int h, int id){
    guielement* newCanvas = (guielement*) new canvas(x, y, w, h, id);
    push_backElement(newCanvas);
}

void gui::CreateToggle(int x, int y, bool init, int id){
    guielement* newToggle = (guielement*) new toggle(id, x, y, init);
    push_backElement(newToggle);
}

void gui::RemoveElement(int id){
    guielement* it = first;
    guielement* previous = NULL;

    while (it != NULL){
        if (it->GetId() == id){
            if (it == lastActivated)
                lastActivated = NULL;
            if (it == last)
                last = previous;
            if (previous == NULL) {
                first = it->GetNext();
                delete it;
                it = first;
            } else {
                previous->SetNext(it->GetNext());
                delete it;
                it = previous->GetNext();
            }
        } else {
            previous = it;
            it = it->GetNext();
        }
    }
}

void gui::SetElementEnabled(bool newEnabled, int id){
    guielement* it = first;
    while (it != NULL){
        if (it->GetId() == id){
            if (newEnabled)
                it->Enable();
            else
                it->Disable();
            return;
        }
        it = it->GetNext();
    }
}

void gui::SetElementText(const char* newText, int id){
    guielement* it = first;
    while (it != NULL){
        if (it->GetId() == id){
            it->SetText(newText);
        }
        it = it->GetNext();
    }
}

guielement* gui::GetElement(int id){
    guielement* it = first;
    while (it != NULL){
        if (it->GetId() == id)
            return it;
        it = it->GetNext();
    }
    return NULL;
}

void gui::Draw(){
    //Reset projection and modelview matrices
    glMatrixMode(GL_PROJECTION);
    glPushMatrix();
    glLoadIdentity();
    glOrtho(0, _WIDTH, 0, _HEIGHT, -1, 1);

    glMatrixMode(GL_MODELVIEW);
    glPushMatrix();
    glLoadIdentity();

    //Draw the gui element list
    guielement* it = first;
    while (it != NULL){
        it->Draw(parent->GetFonts());
        it = it->GetNext();
    }

    //Restore the original projection and modelview matrices
    glMatrixMode(GL_PROJECTION);
    glPopMatrix();

    glMatrixMode(GL_MODELVIEW);
    glPopMatrix();
}

void gui::Flush(){
    guielement* it = first;
    guielement* toDel;
    while (it != NULL){
        toDel = it;
        it = it->GetNext();
        delete toDel;
    }
    first = NULL;
    last = NULL;
    lastActivated = NULL;
}

void gui::push_backElement(guielement* element){
    if (last)
        last->SetNext(element);

    last = element;
    if (first == NULL)
        first = element;
}
